package upnp

import "net/url"

// Device upnp device
type Device struct {
	// url prefix from description location without /, eg: http://192.168.1.1:43051
	urlPrefix string
	// description xml get url
	descLocation string
	// service list for this device
	serviceList []*Service

	parsed bool
}

// NewDevice new device by description url
func NewDevice(desc string) *Device {
	u, _ := url.Parse(desc)
	return &Device{
		urlPrefix:    u.Scheme + "://" + u.Host,
		descLocation: desc,
	}
}

func (d *Device) findAction(name string) ([]Action, error) {
	if err := d.parse(); err != nil {
		return nil, err
	}
	var ret []Action
	for _, srv := range d.serviceList {
		if err := srv.parse(); err != nil {
			return nil, err
		}
		for _, act := range srv.actions {
			if act.Name() == name {
				ret = append(ret, act)
			}
		}
	}
	return ret, nil
}

// GetPortMappingActions get actions with GetGenericPortMappingEntry
func (d *Device) GetPortMappingActions() ([]Action, error) {
	return d.findAction("GetGenericPortMappingEntry")
}

// GetAddMappingActions get actions with AddPortMapping
func (d *Device) GetAddMappingActions() ([]Action, error) {
	return d.findAction("AddPortMapping")
}

// GetDeleteMappingActions get actions with DeletePortMapping
func (d *Device) GetDeleteMappingActions() ([]Action, error) {
	return d.findAction("DeletePortMapping")
}

// GetExtIPActions get actions with GetExternalIPAddress
func (d *Device) GetExtIPActions() ([]Action, error) {
	return d.findAction("GetExternalIPAddress")
}

// ListPortMapping port mapping list
func (d *Device) ListPortMapping() []PortMapping {
	acts, err := d.GetPortMappingActions()
	if err != nil {
		return nil
	}
	if len(acts) != 1 {
		return nil
	}
	act := acts[0].(*GetPortMappingAction)
	var ret []PortMapping
	i := 0
	for {
		resp, err := act.Do(i)
		if IsNotfound(err) {
			break
		}
		if err == nil {
			ret = append(ret, resp.Data.(PortMapping))
		}
		i++
	}
	return ret
}
